#include <iostream>
#include <unistd.h>
#include <vector>
#include <string>
#include <ctime>
#include <sys/wait.h>
#include <sys/stat.h>
#include "Task.hpp"

const int process_num = 10;
std::vector<task_t> tasks;

//先描述 描述管道
class channel
{
public:
    channel(int cmdfd, pid_t process_pid, std::string process_name)
        : _cmdfd(cmdfd)
        , _process_pid(process_pid)
        , _process_name(process_name) 
        {}

public:
    int _cmdfd;   // 发送任务的文件描述符
    pid_t _process_pid;   // 子进程的pid
    std::string _process_name; 
};


void slaver()
{
    // 直接从 0 读取
    // read(0)
    while(1)
    {
        int cmdcode = 0;
        int n = read(0, &cmdcode, sizeof(cmdcode));
        if(n == sizeof(cmdcode))
        {
            // 执行任务码所代表的任务
            std::cout << "#child say : process " << getpid() << " get a cmdcode " << cmdcode << std::endl; 
            if(cmdcode >= 0 && cmdcode < tasks.size())
            {
                tasks[cmdcode]();
            }
        }
        else if(n == 0)
        {
            break;
        }
        //sleep(1000);
    }
}
 

void InitProcessPool(std::vector<channel>& channels)
{
    std::vector<int> oldfd;
    // 初始化
    for(int i = 0; i < process_num; i++)
    {
        //创建管道
        int pipefd[2];
        int n1 = pipe(pipefd);
        if(n1 < 0)
        {
            std::cout << "pipe fail" << std::endl;
            break;
        } 
        //创建子进程
        pid_t pid = fork();
        if(pid == 0)
        {
            // child
            close(pipefd[1]);

            //关闭从父进程那里得到的w端
            for(auto fd : oldfd)
            {
                close(fd);
            }

            //std::cout << "child " << getpid() << std::endl; 
            //slaver(pipefd[0]);
            dup2(pipefd[0], 0);
            close(pipefd[0]);
            slaver();
            std::cout << "quit procss " << getpid() << std::endl;
            exit(0);
        }
        else if(pid < 0)
        {
            std::cout << "fork fail" << std::endl;
            break;
        }

        // father
        // 添加字段
        close(pipefd[0]);
        std::string name = "process - " + std::to_string(i);  
        channels.push_back(channel(pipefd[1], pid, name));
        oldfd.push_back(pipefd[1]);
    }
}

void Debug(const std::vector<channel>& channels)
{
    
    for(auto& ch : channels)
    {
        std::cout << " _cmdfd : "<< ch._cmdfd << " pid : " << ch._process_pid << " " << ch._process_name << std::endl;  
    }
}

void Menu()
{
    std::cout << "################################################" << std::endl;
    std::cout << "# 1. 刷新日志             2. 刷新野区            #" << std::endl;
    std::cout << "# 3. 检测更新             4. 释放技能            #" << std::endl;
    std::cout << "#                 0. 退出                       #" << std::endl;
    std::cout << "#################################################" << std::endl;
}

void CtrlSlaver(const std::vector<channel>& channels)
{
    for(int i = 1; i > 0; i++)
    {
        // 1，选择任务
        //int cmdcode = rand() % tasks.size();
        Menu();
        int cmdcode = 0;
        std::cin >> cmdcode;
        if(cmdcode == 0)
        {
            break;
        }
        cmdcode--;
        // 2，选择进程
        int process_pos = rand() % channels.size(); 

        // 3，发送任务
        std::cout << "@father say "<< " cmdcode " << cmdcode << " already sent to process " 
        << channels[process_pos]._process_pid 
        << " " << channels[process_pos]._process_name << std::endl;
        write(channels[process_pos]._cmdfd, &cmdcode, sizeof(cmdcode));
        sleep(1);
    }
}



void QuitProcess(const std::vector<channel>& channels)
{
    // 子进程关闭写入端
    for(auto& ch : channels)
    {
        close(ch._cmdfd);
    }

    sleep(5);

    //父进程waitpid
    for(auto& ch : channels)
    {
        waitpid(ch._process_pid, nullptr, 0);
    }
}

int main()
{
    LoadTask(&tasks);

    srandom(time(nullptr) ^ 3482);
    // 初始化
    std::vector<channel> channels;
    InitProcessPool(channels);
    Debug(channels);

    // 2，开始控制子进程
    CtrlSlaver(channels);

    // 3，清理收尾
    QuitProcess(channels);

    //sleep(100);
    return 0;
}
